package me.zhengjie.modules.hanzi.utils;

import lombok.extern.slf4j.Slf4j;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.ConvolveOp;
import java.awt.image.Kernel;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;

/**
 * 图像处理工具类
 */
@Slf4j
public class ImageProcessingUtils {

    /**
     * 从输入流读取图像
     */
    public static BufferedImage readImage(InputStream inputStream) throws IOException {
        return ImageIO.read(inputStream);
    }

    public static BufferedImage urlToBufferedImage(String imageUrl) throws IOException {
        URL url = new URL(imageUrl);
        return ImageIO.read(url);
    }

    /**
     * 调整图像大小
     */
    public static BufferedImage resizeImage(BufferedImage originalImage, int targetWidth, int targetHeight) {
        BufferedImage resizedImage = new BufferedImage(targetWidth, targetHeight, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = resizedImage.createGraphics();
        g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        g.drawImage(originalImage, 0, 0, targetWidth, targetHeight, null);
        g.dispose();
        return resizedImage;
    }

    /**
     * 转换为灰度图像
     */
    public static BufferedImage toGrayscale(BufferedImage image) {
        BufferedImage grayImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
        Graphics g = grayImage.getGraphics();
        g.drawImage(image, 0, 0, null);
        g.dispose();
        return grayImage;
    }

    /**
     * 使用Otsu算法进行二值化处理
     */
    public static BufferedImage binarizeWithOtsu(BufferedImage grayImage) {
        int threshold = calculateOtsuThreshold(grayImage);
        return binarize(grayImage, threshold);
    }

    /**
     * 使用给定阈值进行二值化处理
     */
    public static BufferedImage binarize(BufferedImage grayImage, int threshold) {
        BufferedImage binaryImage = new BufferedImage(grayImage.getWidth(), grayImage.getHeight(),
                BufferedImage.TYPE_BYTE_BINARY);

        for (int x = 0; x < grayImage.getWidth(); x++) {
            for (int y = 0; y < grayImage.getHeight(); y++) {
                int grayValue = grayImage.getRGB(x, y) & 0xFF;
                if (grayValue > threshold) {
                    binaryImage.setRGB(x, y, Color.WHITE.getRGB());
                } else {
                    binaryImage.setRGB(x, y, Color.BLACK.getRGB());
                }
            }
        }
        return binaryImage;
    }

    /**
     * 计算Otsu阈值
     */
    public static int calculateOtsuThreshold(BufferedImage grayImage) {
        int[] histogram = new int[256];

        // 计算灰度直方图
        for (int x = 0; x < grayImage.getWidth(); x++) {
            for (int y = 0; y < grayImage.getHeight(); y++) {
                int grayValue = grayImage.getRGB(x, y) & 0xFF;
                histogram[grayValue]++;
            }
        }

        int total = grayImage.getWidth() * grayImage.getHeight();
        float sum = 0;
        for (int i = 0; i < 256; i++) {
            sum += i * histogram[i];
        }

        float sumB = 0;
        int wB = 0;
        int wF;
        float maxVariance = 0;
        int threshold = 0;

        for (int i = 0; i < 256; i++) {
            wB += histogram[i];
            if (wB == 0) continue;

            wF = total - wB;
            if (wF == 0) break;

            sumB += i * histogram[i];
            float mB = sumB / wB;
            float mF = (sum - sumB) / wF;

            float varianceBetween = wB * wF * (mB - mF) * (mB - mF);

            if (varianceBetween > maxVariance) {
                maxVariance = varianceBetween;
                threshold = i;
            }
        }

        return threshold;
    }

    /**
     * 应用高斯模糊
     */
    public static BufferedImage applyGaussianBlur(BufferedImage image) {
        float[] matrix = {
                1/16f, 2/16f, 1/16f,
                2/16f, 4/16f, 2/16f,
                1/16f, 2/16f, 1/16f
        };
        BufferedImage output = new BufferedImage(image.getWidth(), image.getHeight(), image.getType());
        ConvolveOp op = new ConvolveOp(new Kernel(3, 3, matrix), ConvolveOp.EDGE_NO_OP, null);
        op.filter(image, output);
        return output;
    }

    /**
     * 应用中值滤波去噪
     */
    public static BufferedImage applyMedianFilter(BufferedImage image, int size) {
        int width = image.getWidth();
        int height = image.getHeight();
        BufferedImage result = new BufferedImage(width, height, image.getType());

        int[] pixels = new int[(2 * size + 1) * (2 * size + 1)];

        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                int index = 0;
                for (int dy = -size; dy <= size; dy++) {
                    for (int dx = -size; dx <= size; dx++) {
                        int nx = x + dx;
                        int ny = y + dy;
                        if (nx >= 0 && nx < width && ny >= 0 && ny < height) {
                            pixels[index++] = image.getRGB(nx, ny) & 0xFF;
                        } else {
                            pixels[index++] = 0;
                        }
                    }
                }

                // 对像素值进行排序并取中值
                java.util.Arrays.sort(pixels, 0, index);
                int median = pixels[index / 2];

                // 设置结果图像的像素值
                int rgb = (median << 16) | (median << 8) | median;
                result.setRGB(x, y, rgb);
            }
        }

        return result;
    }

    /**
     * 计算两个图像的相似度（使用像素匹配）
     */
    public static double calculateSimilarity(BufferedImage img1, BufferedImage img2) {
        if (img1.getWidth() != img2.getWidth() || img1.getHeight() != img2.getHeight()) {
            throw new IllegalArgumentException("图像尺寸不匹配");
        }

        int width = img1.getWidth();
        int height = img1.getHeight();
        int matchCount = 0;
        int totalPixels = width * height;

        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                if ((img1.getRGB(x, y) & 0xFFFFFF) == (img2.getRGB(x, y) & 0xFFFFFF)) {
                    matchCount++;
                }
            }
        }

        return (double) matchCount / totalPixels;
    }

    /**
     * 提取图像轮廓
     */
    public static BufferedImage extractContour(BufferedImage binaryImage) {
        int width = binaryImage.getWidth();
        int height = binaryImage.getHeight();
        BufferedImage contourImage = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_BINARY);

        // 初始化轮廓图像为白色
        Graphics2D g = contourImage.createGraphics();
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, width, height);
        g.dispose();

        // 检测边缘像素
        for (int x = 1; x < width - 1; x++) {
            for (int y = 1; y < height - 1; y++) {
                // 如果当前像素是黑色（前景）
                if ((binaryImage.getRGB(x, y) & 0xFFFFFF) == 0) {
                    // 检查8个相邻像素是否有白色（背景）
                    boolean isEdge = false;
                    for (int dx = -1; dx <= 1 && !isEdge; dx++) {
                        for (int dy = -1; dy <= 1 && !isEdge; dy++) {
                            if (dx == 0 && dy == 0) continue;
                            
                            if ((binaryImage.getRGB(x + dx, y + dy) & 0xFFFFFF) == 0xFFFFFF) {
                                isEdge = true;
                            }
                        }
                    }
                    
                    // 如果是边缘像素，在轮廓图像中标记为黑色
                    if (isEdge) {
                        contourImage.setRGB(x, y, Color.BLACK.getRGB());
                    }
                }
            }
        }

        return contourImage;
    }

    /**
     * 计算图像的重心
     * @return 返回一个包含x和y坐标的数组
     */
    public static double[] calculateCenterOfMass(BufferedImage binaryImage) {
        int width = binaryImage.getWidth();
        int height = binaryImage.getHeight();
        int totalBlackPixels = 0;
        int sumX = 0;
        int sumY = 0;

        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                if ((binaryImage.getRGB(x, y) & 0xFFFFFF) == 0) { // 黑色像素
                    totalBlackPixels++;
                    sumX += x;
                    sumY += y;
                }
            }
        }

        if (totalBlackPixels == 0) {
            return new double[]{width / 2.0, height / 2.0}; // 如果没有黑色像素，返回图像中心
        }

        double centerX = (double) sumX / totalBlackPixels;
        double centerY = (double) sumY / totalBlackPixels;

        return new double[]{centerX, centerY};
    }

    /**
     * 计算图像的对称性
     * @return 返回对称性得分（0-1之间，越接近1表示越对称）
     */
    public static double calculateSymmetry(BufferedImage img) {
        int width = img.getWidth();
        int height = img.getHeight();
        int midX = width / 2;
        int midY = height / 2;
        
        int horizontalMatchCount = 0;
        int horizontalTotalPixels = (width / 2) * height;
        
        // 水平对称性
        for (int x = 0; x < midX; x++) {
            for (int y = 0; y < height; y++) {
                if ((img.getRGB(x, y) & 0xFFFFFF) == (img.getRGB(width - 1 - x, y) & 0xFFFFFF)) {
                    horizontalMatchCount++;
                }
            }
        }
        
        double horizontalSymmetry = (double) horizontalMatchCount / horizontalTotalPixels;
        
        // 垂直对称性
        int verticalMatchCount = 0;
        int verticalTotalPixels = width * (height / 2);
        
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < midY; y++) {
                if ((img.getRGB(x, y) & 0xFFFFFF) == (img.getRGB(x, height - 1 - y) & 0xFFFFFF)) {
                    verticalMatchCount++;
                }
            }
        }
        
        double verticalSymmetry = (double) verticalMatchCount / verticalTotalPixels;
        
        // 取平均值
        return (horizontalSymmetry + verticalSymmetry) / 2;
    }
} 